import numpy as np  
import time
import sys 
import cv2

import proto.cameraobjectarray_pb2 as cameraobjectarray_pb2


class VehicleCount:
    def __init__(self, line_start,line_end,max_track_length,unupdated_timeout,
                 calculate_range_flag=True,
                 identification_range=30):  
        self.prev_time = time.time()  #帧计数器
        # 定义识别线线的起点和终点坐标
        self.line_start = line_start  # 起点
        self.line_end = line_end  # 终点
        self.counter = 0  # 计数器
        self.counter_id = 0  # 分配唯一 ID 的计数器
        self.buffer_tracks = {}  # 保存位置和时间的元组
        self.crossed_boxes = {}  # 用于存储每个框的交叉状态的字典
        self.calculate_range_flag = calculate_range_flag   #
        self.identification_range = identification_range  # 连续框判断误差（像素）
        self.max_track_length = max_track_length  # 最大轨迹长度
        self.unupdated_timeout = unupdated_timeout  # 未更新的轨迹存在时间（秒）
        self.last_updated = {}  # 初始化 last_updated 字典
        
        self.line_start = np.array([150, 480])  # 起点
    	self.line_end = np.array([900, 480])  # 终点
    	
    	self.way3_line_start = np.array([150, 480])  # 起点
    	self.way3_line_end = np.array([900, 480])  # 终点
        
        self.change_line_start = np.array([150, 480])  # 起点
        self.change_line_end = np.array([900, 480])  # 终点
        
        self.change3_line_start = np.array([150, 480])  # 起点
        self.change3_line_end = np.array([900, 480])  # 终点
        
        self.ill_line_start = np.array([150, 480])  # 起点
        self.ill_line_end = np.array([900, 480])  # 终点
        
        self.ill3_line_start = np.array([150, 480])  # 起点
        self.ill3_line_end = np.array([900, 480])  # 终点
    	
    	
    	self.way3_counter=0
    	self.truck_counter=0
    	
    	self.change_counter=0
    	self.change_boxes={}
    	
    	self.person_counter=0
    	self.ill_counter=0
    	self.ill_time=0
    	self.ill_flag=False
    	self.ill_type=0
    	
	

    def calculate_identification_range(self, y, frame_height, min_range=5, max_range=70):
        """
        根据 y 坐标动态计算识别范围。
        y: 车辆中心的 y 坐标
        frame_height: 视频帧的高度
        min_range: 最小识别范围
        max_range: 最大识别范围
        """
        return int(min_range + (max_range - min_range) * (y / frame_height))
    
    def estimate_cross_and_count(self,box_id,type):
        if len(self.buffer_tracks[box_id])>1 and not self.crossed_boxes[box_id]:
        	if (self.buffer_tracks[box_id][-2][0][1]-self.line_start[1])*(self.buffer_tracks[box_id][-1][0][1]-self.line_start[1])<=0:
        		if(self.buffer_tracks[box_id][-2][0][0]>=self.line_start[0]) and (self.buffer_tracks[box_id][-2][0][0]<=self.line_end[0]):
        			self.crossed_boxes[box_id]=True
        			self.counter+=1
        			if type=="turck":
        				self.truck_counter+=1
        	if (self.buffer_tracks[box_id][-2][0][1]-self.way3_line_start[1])*(self.buffer_tracks[box_id][-1][0][1]-self.way3_line_start[1])<=0:
        		if(self.buffer_tracks[box_id][-2][0][0]>=self.way3_line_start[0]) and (self.buffer_tracks[box_id][-2][0][0]<=self.way3_line_end[0]):
        			self.crossed_boxes[box_id]=True
        			self.way3_counter+=1
        			if type=="person":
        				self.person_counter+=1
        				
        				
    def change_cross_and_count(self,box_id,type):
        if len(self.buffer_tracks[box_id])>1 :
        	if self.buffer_tracks[box_id][-2][0][1]>self.change_line_start[1]:
        		x1=self.change_line_start[0]
        		y1=self.change_line_start[1]
        		x2=self.change_line_end[0]
        		y2=self.change_line_end[1]
        		
        		x3=self.buffer_tracks[box_id][-2][0][0]
        		y3=self.buffer_tracks[box_id][-2][0][1]
        		x4=self.buffer_tracks[box_id][-1][0][0]
        		y4=self.buffer_tracks[box_id][-1][0][1]
        		pan1=(x2-x1)*(y3-y1)-(y2-y1)*(x3-x1)
        		pan2=(x2-x1)*(y4-y1)-(y2-y1)*(x4-x1)
        		
        		if pan1*pan2<=0:
        			if not self.change_boxes[box_id]:
        				self.change_boxes[box_id]=True
        				self.change_cunter+=1
        			if y3>=self.ill_line_start[1]:
        				self.ill_counter+=1
        				
        				
    def change3_cross_and_count(self,box_id,type):
        if len(self.buffer_tracks[box_id])>1 :
        	if self.buffer_tracks[box_id][-2][0][1]<=self.change3_line_start[1]:
        		x1=self.change3_line_start[0]
        		y1=self.change3_line_start[1]
        		x2=self.change3_line_end[0]
        		y2=self.change3_line_end[1]
        		
        		x3=self.buffer_tracks[box_id][-2][0][0]
        		y3=self.buffer_tracks[box_id][-2][0][1]
        		x4=self.buffer_tracks[box_id][-1][0][0]
        		y4=self.buffer_tracks[box_id][-1][0][1]
        		pan1=(x2-x1)*(y3-y1)-(y2-y1)*(x3-x1)
        		pan2=(x2-x1)*(y4-y1)-(y2-y1)*(x4-x1)
        		
        		if pan1*pan2<=0:
        			if not self.ill_flag and y<=self.ill3_line_start[1]:
        				self.ill_time=self.prev_time
        				self.ill_flage=True
        				self.ill_type="ill_change"
        				
        			
        				
        		

    def remove_old_tracks(self):
        for id, track in list(self.buffer_tracks.items()):
            if len(track) > self.max_track_length:  # 如果轨迹过长
                track.pop(0)  # 移除最旧的位置
                #if time.time() - track[-1][1] > track_timeout:  #
                    #del buffer_tracks[id]  # 删除整个轨迹

        for id in list(self.buffer_tracks.keys()):
            if time.time() - self.last_updated[id] > self.unupdated_timeout:  #
                del self.buffer_tracks[id]  # 删除整个轨迹
                del self.last_updated[id]  # 删除对应的时间  

    def count(self,xobjarray : cameraobjectarray_pb2.cameraobjectarray,pic_mat : np):
        start_time = time.time()  # 记录处理开始时间
        frame_height = pic_mat.shape[0]  # 获取帧的高度
        curr_time = time.time()
        FPS = 1 / (curr_time - self.prev_time)
        self.prev_time = curr_time
        FPS_str = 'FPS: %s' % round(FPS, 2)
        # 绘制边界框和 FPS
        #cv2.putText(pic_mat, FPS_str, (5, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (34, 139, 34), 2)   
        for pobj in xobjarray.obj:

            center = np.array([(pobj.x + 0.5*pobj.w), (pobj.y + 0.5*pobj.h)], dtype=int)
            cv2.circle(pic_mat, tuple(center), radius=5, color=(0, 255, 255), thickness=-1)
            cv2.line(pic_mat, tuple(self.line_start), tuple(self.line_end), color=(255, 0, 255), thickness=6)
            cv2.line(pic_mat,tuple(self.way3_line_start),tuple(self.way3_line_end),color=(0,255,0),thickness=6)
            cv2.line(pic_mat,tuple(self.change_line_start),tuple(self.change_line_end),color=(0,0,255),thickness=6)
            cv2.line(pic_mat,tuple(self.change3_line_start),tuple(self.change3_line_end),color=(0,0,255),thickness=6)
            cv2.line(pic_mat,tuple(self.ill_line_start),tuple(self.ill_line_end),color=(0,0,255),thickness=6)
            cv2.line(pic_mat,tuple(self.ill3_line_start),tuple(self.ill3_line_end),color=(0,0,255),thickness=6)
            
            

            # 动态计算识别范围
            identification_range = self.calculate_identification_range(center[1], frame_height) if self.calculate_range_flag else self.identification_range

            # 检查框 ID 是否已存在于缓冲区中
            box_id = None
            for id, past_positions in self.buffer_tracks.items():
                if len(past_positions) > 0 and np.linalg.norm(
                        past_positions[-1][0] - center) < identification_range:
                    box_id = id
                    break

            if box_id is None:
                # 分配一个新的 ID为盒子
                box_id = self.counter_id
                self.counter_id += 1
                self.buffer_tracks[box_id] = []
                self.crossed_boxes[box_id] = False  # 将交叉状态初始化为 Fals
                self.change_boxes[box_id]=False
            self.buffer_tracks[box_id].append((center, time.time()))  # 添加位置和当前时间
            self.last_updated[box_id] = time.time()  # 更新时间

            # 绘制检测框的ID
            cv2.putText(pic_mat, f'ID: {box_id}', (center[0], center[1] - 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2)

            # 检查框是否越界
            self.estimate_cross_and_count(box_id,pobj.type)
            
            self.change_and_count(box_id,pobj.type)
            self.change3_and_count(box_id,pobj.type)

            # 如果框被标记为已越线，则绘制文本
            if self.crossed_boxes[box_id]:
                cv2.putText(pic_mat, 'crossed', (center[0], center[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, 1,
                            (0, 255, 0), 2)
                
        # delete old tracker
        self.remove_old_tracks()

        #draw track
        for track in self.buffer_tracks.values():
            positions = [pos_time[0] for pos_time in track]  # 提取位置列表
            if len(positions) > 1:
                for i in range(1, len(positions)):
                    start_pos = positions[i - 1]
                    end_pos = positions[i]
                    cv2.line(pic_mat, tuple(start_pos), tuple(end_pos), (0, 255, 255), 4)  # 轨迹线条

        counter_str = 'Counter: %s' % self.counter
        counter_str1 = f"counter1_2:{self.counter},truck_counter:{self.truck_counter},change_counter1_2:{self.change_counter},ill_counter:{self.ill_counter}"
        counter_str2 = f"counter3:{self.way3_counter},person_counter:{self.person_counter},ill_time={self.ill_time},ill_type={self.ill_type}"
        cv2.putText(pic_mat, counter_str, (5, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)  # 将计数器放在框架上
        cv2.putText(pic_mat, counter_str, (5, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)  # 将计数器放在框架上
                

                
                
                    


    
    

    



    
